import math
from endOfSanity import *
from basicEdge import basicEdge

class edge(basicEdge):

    @staticmethod
    def fromBasicEdge(basicEdge, dictionary):
        """
        Create an edge from an basicEdge instance. In the argument dictionary 
        there is a mapping from the basicNodes to the nodes.
        """
        result = edge( dictionary[basicEdge.startNode],\
            dictionary[basicEdge.endNode], basicEdge.ID)        
        result.priority = basicEdge.priority
        return result
        
    def __init__(self,start, end,ID):
        """
        Create an (directed) edge. 
        
        Arguments:
        
        start -- start node of the edge,
        end -- end node of the edge,
        ID -- identifier of the edge.
        """
        basicEdge.__init__(self,start,end,ID)
        self.carList = []
          
    def __repr__(self):
        return "(" + str(self.startNode.ID) + "," + str(self.endNode.ID) + ")"
       
    def occupancy(self):
        """
        Check whether any car contained in this edge is also contained in either 
        startNode or endNode of this edge.
        """
        for car in self.carList:
            if car.position - car.radius < self.startNode.radius:
                self.startNode.isSomeoneInside = car
            if self.length() - car.position - car.radius < self.endNode.radius:
                self.endNode.isSomeoneInside = car
                
    def checkColision(self,position,speed,car):
        """
        Check whether car given in argument can collide with either a car 
        contained in this edge or with it's endNode (if it is reserved). The
        collision is checked on assumption that in the next turn:
        * car from the argument will have speed as one given in the argument
        * all cars from the edge won't move in the next round.
        
        Return a tuple. First element of a tuple is a float saying how for a 
        car can go wihout a collision (or it's speed if there is no collision). 
        Second element of a tuple is a bollean value, saying whether there is 
        collision.
        
        """
        collision = False
        for carFromList in self.carList:
            if carFromList.position == position:
                # There may be only one car in the one position.
                assert carFromList == car 
            elif carFromList.position < position: 
                # carFromList is on the left from our car, 
                # therefore they can't collide
                pass 
            elif  carFromList.position <= position + speed + carFromList.radius\
                + car.radius:
                collision = True
                speed = max( carFromList.position - position -\
                    (carFromList.radius + car.radius) , 0 )
        # Now, checking the collision with the endNode of the edge takes place.
        if position + speed > self.length() - self.endNode.radius - car.radius:  
           if not self.endNode.checkColision(car):
               collision = True
               # Distance that a car can go without collision with a node
               # is a distance between a car a node, minus sum of their
               # radius.
               to_node = self.length() - position - self.endNode.radius -\
                   car.radius 
               return ( max( to_node , 0 ), True ) # Collision with a node
           else:
                return ( speed, collision ) # No collision with a node
        else:
            return ( speed, collision ) # No chance of colliding with a node
        
    def addCar(self,car):
        """ Place a car in the edge. """        
        self.carList = [car] + self.carList
                
    def removeCar(self, car):
        """ Remove a car from the edge"""
        self.carList.remove(car)
